package org.budo.accesslog.entity.builder;

import javax.servlet.http.HttpServletRequest;

import org.budo.accesslog.entity.AccesslogEntity;
import org.budo.accesslog.entity.BudoAccesslogEntity;
import org.budo.dubbo.protocol.http.authentication.AuthenticationCheckService;
import org.budo.support.lang.util.ReflectUtil;
import org.budo.support.lang.util.StringUtil;
import org.budo.support.mvcs.Mvcs;
import org.budo.support.spring.util.SpringUtil;
import org.budo.time.Time;

import com.alibaba.fastjson.JSON;

/**
 * @author lmw
 */
public class BudoAccesslogEntityBuilder implements AccesslogEntityBuilder {
    private static final Boolean HAS_CLASS_AUTHENTICATION_CHECK_SERVICE = ReflectUtil.hasClass("org.budo.dubbo.protocol.http.authentication.AuthenticationCheckService");

    public static final BudoAccesslogEntityBuilder INSTANCE = new BudoAccesslogEntityBuilder();

    @Override
    public AccesslogEntity buildAccesslogEntity(HttpServletRequest request) {
        String queryString = Mvcs.getQueryString();

        String method = Mvcs.getMethod(request);
        String remoteAddr = Mvcs.getRemoteAddr(request);
        String serverName = Mvcs.getServerName(request);
        String userAgent = Mvcs.getUserAgent(request);
        Object handler = Mvcs.getHandler();

        Object principalInRequest = this.principal();

        AccesslogEntity accesslogEntity = this.initAccesslogEntity();

        String requestURI = Mvcs.getRequestURI(request);

        String requestBody = this.requestBody();
        if (null != requestBody && !requestBody.isEmpty()) { // 如果有 requestBody; queryString 放在 requestUri
            accesslogEntity.setRequestBody(requestBody);
            accesslogEntity.setRequestUri(requestURI + "?" + queryString);
        } else {
            accesslogEntity.setRequestBody(queryString); // 如果没有 requestBody; queryString 放在 requestBody
            accesslogEntity.setRequestUri(requestURI);
        }

        accesslogEntity.setType(method);
        accesslogEntity.setRemoteAddr(remoteAddr);
        accesslogEntity.setCreatedAt(Time.now().toTimestamp());

        accesslogEntity.setServerName(serverName);
        accesslogEntity.setUserAgent(userAgent);

        accesslogEntity.setHandler(null == handler ? null : handler.toString());

        if (null != principalInRequest) {
            String remoteUser = JSON.toJSONString(principalInRequest);
            accesslogEntity.setRemoteUser(remoteUser);
        }

        return accesslogEntity;
    }

    protected AccesslogEntity initAccesslogEntity() {
        return new BudoAccesslogEntity();
    }

    private Object principal() {
        Object attribute = Mvcs.getRequestAttribute("PrincipalInRequest");
        if (null != attribute) {
            return attribute;
        }

        if (!HAS_CLASS_AUTHENTICATION_CHECK_SERVICE) {
            return null;
        }

        AuthenticationCheckService authenticationCheckService = SpringUtil.getBean(AuthenticationCheckService.class);
        if (null == authenticationCheckService) {
            return null;
        }

        return authenticationCheckService.getAuthenticationPrincipal();
    }

    private String requestBody() {
        String requestBody = Mvcs.getRequestBody();
        if (null == requestBody || requestBody.length() < 1024) {
            return requestBody;
        }

        return StringUtil.cutLeft(requestBody, 1024, "...");
    }
}